/**
 * PLC设备适配器基类
 * 为不同品牌和型号的PLC提供统一接口
 */
const EventEmitter = require('events');
const logger = require('../utils/logger');

class PLCAdapter extends EventEmitter {
  constructor(device) {
    super();
    this.device = device;
    this.client = null;
    this.connected = false;
    this.pollIntervals = {};
    this.heartbeatInterval = null;
  }

  /**
   * 初始化PLC连接
   */
  async initialize() {
    throw new Error('必须在子类中实现initialize方法');
  }

  /**
   * 断开PLC连接
   */
  async disconnect() {
    throw new Error('必须在子类中实现disconnect方法');
  }

  /**
   * 读取标签值
   * @param {string} tagName - 标签名称
   */
  async readTag(tagName) {
    throw new Error('必须在子类中实现readTag方法');
  }

  /**
   * 写入标签值
   * @param {string} tagName - 标签名称
   * @param {any} value - 写入值
   */
  async writeTag(tagName, value) {
    throw new Error('必须在子类中实现writeTag方法');
  }

  /**
   * 读取所有标签值
   */
  async readAllTags() {
    throw new Error('必须在子类中实现readAllTags方法');
  }

  /**
   * 启动数据轮询
   * @param {string} tagName - 标签名称
   * @param {number} interval - 轮询间隔(毫秒)
   * @param {Function} callback - 回调函数
   */
  startPolling(tagName, interval, callback) {
    if (this.pollIntervals[tagName]) {
      this.stopPolling(tagName);
    }

    logger.info(`[${this.device.id}] 开始轮询标签: ${tagName}, 间隔: ${interval}ms`);
    
    this.pollIntervals[tagName] = setInterval(async () => {
      try {
        const value = await this.readTag(tagName);
        callback(null, value);
      } catch (error) {
        callback(error);
      }
    }, interval);
  }

  /**
   * 停止数据轮询
   * @param {string} tagName - 标签名称
   */
  stopPolling(tagName) {
    if (this.pollIntervals[tagName]) {
      clearInterval(this.pollIntervals[tagName]);
      delete this.pollIntervals[tagName];
      logger.info(`[${this.device.id}] 停止轮询标签: ${tagName}`);
    }
  }

  /**
   * 停止所有数据轮询
   */
  stopAllPolling() {
    Object.keys(this.pollIntervals).forEach(tagName => {
      this.stopPolling(tagName);
    });
  }

  /**
   * 启动心跳检测
   * @param {number} interval - 心跳间隔(毫秒)
   */
  startHeartbeat(interval) {
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
    }

    logger.info(`[${this.device.id}] 启动心跳检测, 间隔: ${interval}ms`);
    
    this.heartbeatInterval = setInterval(async () => {
      try {
        await this.sendHeartbeat();
      } catch (error) {
        logger.error(`[${this.device.id}] 心跳检测失败: ${error.message}`);
      }
    }, interval);
  }

  /**
   * 停止心跳检测
   */
  stopHeartbeat() {
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
      this.heartbeatInterval = null;
      logger.info(`[${this.device.id}] 停止心跳检测`);
    }
  }

  /**
   * 发送心跳检测
   */
  async sendHeartbeat() {
    throw new Error('必须在子类中实现sendHeartbeat方法');
  }

  /**
   * 解析地址
   * @param {string} address - 地址字符串
   */
  parseAddress(address) {
    // 解析Modbus地址格式
    // 例如: 40001 -> { type: 'holdingRegister', address: 0 }
    const addressStr = String(address);
    let type, offset;

    if (addressStr.startsWith('0') || addressStr.startsWith('00')) {
      type = 'coil';
      offset = parseInt(addressStr.substring(2), 10) - 1;
    } else if (addressStr.startsWith('1') || addressStr.startsWith('10')) {
      type = 'discreteInput';
      offset = parseInt(addressStr.substring(2), 10) - 1;
    } else if (addressStr.startsWith('3') || addressStr.startsWith('30')) {
      type = 'inputRegister';
      offset = parseInt(addressStr.substring(2), 10) - 1;
    } else if (addressStr.startsWith('4') || addressStr.startsWith('40')) {
      type = 'holdingRegister';
      offset = parseInt(addressStr.substring(2), 10) - 1;
    } else {
      throw new Error(`无效的地址格式: ${address}`);
    }

    return { type, address: offset };
  }

  /**
   * 转换数据类型
   * @param {Array} data - 原始数据
   * @param {string} dataType - 数据类型
   * @param {number} scaleFactor - 缩放因子
   */
  convertDataType(data, dataType, scaleFactor = 1) {
    switch (dataType) {
      case 'boolean':
        return !!data[0];
      
      case 'int16':
        return data[0];
      
      case 'uint16':
        return data[0] & 0xFFFF;
      
      case 'int32':
        return (data[0] << 16) | data[1];
      
      case 'uint32':
        return ((data[0] << 16) | data[1]) >>> 0;
      
      case 'float':
        // 假设是两个寄存器组成的IEEE-754浮点数
        const buf = Buffer.alloc(4);
        buf.writeUInt16BE(data[0], 0);
        buf.writeUInt16BE(data[1], 2);
        return buf.readFloatBE(0) * scaleFactor;
      
      default:
        return data;
    }
  }

  /**
   * 将值转换为寄存器格式
   * @param {any} value - 输入值
   * @param {string} dataType - 数据类型
   * @param {number} scaleFactor - 缩放因子
   */
  convertToRegisters(value, dataType, scaleFactor = 1) {
    switch (dataType) {
      case 'boolean':
        return [value ? 1 : 0];
      
      case 'int16':
      case 'uint16':
        return [parseInt(value, 10)];
      
      case 'int32':
      case 'uint32': {
        const val = parseInt(value, 10);
        return [(val >> 16) & 0xFFFF, val & 0xFFFF];
      }
      
      case 'float': {
        const val = parseFloat(value) / scaleFactor;
        const buf = Buffer.alloc(4);
        buf.writeFloatBE(val, 0);
        return [buf.readUInt16BE(0), buf.readUInt16BE(2)];
      }
      
      default:
        return [parseInt(value, 10)];
    }
  }
}

module.exports = PLCAdapter;
